package com.ai.learning.framework.common.util;

import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * Redis工具类
 * 生产级Redis操作封装，支持各种数据类型操作
 * 与Python Django-Redis保持API一致性
 */
@Slf4j
@Component
@ConditionalOnClass(RedisTemplate.class)
public class RedisHelper {

    private final RedisTemplate<String, Object> redisTemplate;

    public RedisHelper(RedisTemplate<String, Object> redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    // ========== 通用操作 ==========

    /**
     * 删除缓存
     */
    public Boolean delete(String key) {
        try {
            return redisTemplate.delete(key);
        } catch (Exception e) {
            log.error("删除缓存失败, key: {}", key, e);
            return false;
        }
    }

    /**
     * 批量删除缓存
     */
    public Long delete(Collection<String> keys) {
        try {
            return redisTemplate.delete(keys);
        } catch (Exception e) {
            log.error("批量删除缓存失败, keys: {}", keys, e);
            return 0L;
        }
    }

    /**
     * 检查key是否存在
     */
    public Boolean hasKey(String key) {
        try {
            return redisTemplate.hasKey(key);
        } catch (Exception e) {
            log.error("检查key存在性失败, key: {}", key, e);
            return false;
        }
    }

    /**
     * 设置key过期时间
     */
    public Boolean expire(String key, long seconds) {
        try {
            return redisTemplate.expire(key, seconds, TimeUnit.SECONDS);
        } catch (Exception e) {
            log.error("设置过期时间失败, key: {}, seconds: {}", key, seconds, e);
            return false;
        }
    }

    /**
     * 获取key的过期时间（秒）
     */
    public Long getExpire(String key) {
        try {
            return redisTemplate.getExpire(key, TimeUnit.SECONDS);
        } catch (Exception e) {
            log.error("获取过期时间失败, key: {}", key, e);
            return -1L;
        }
    }

    // ========== String操作 ==========

    /**
     * 设置字符串值（永不过期）
     */
    public Boolean set(String key, Object value) {
        try {
            redisTemplate.opsForValue().set(key, value);
            return true;
        } catch (Exception e) {
            log.error("设置缓存失败, key: {}, value: {}", key, value, e);
            return false;
        }
    }

    /**
     * 设置字符串值（带过期时间）
     */
    public Boolean set(String key, Object value, long seconds) {
        try {
            if (seconds > 0) {
                redisTemplate.opsForValue().set(key, value, seconds, TimeUnit.SECONDS);
            } else {
                redisTemplate.opsForValue().set(key, value);
            }
            return true;
        } catch (Exception e) {
            log.error("设置缓存失败, key: {}, value: {}, seconds: {}", key, value, seconds, e);
            return false;
        }
    }

    /**
     * 获取字符串值
     */
    public Object get(String key) {
        try {
            return redisTemplate.opsForValue().get(key);
        } catch (Exception e) {
            log.error("获取缓存失败, key: {}", key, e);
            return null;
        }
    }

    /**
     * 获取字符串值（泛型版本）
     */
    @SuppressWarnings("unchecked")
    public <T> T get(String key, Class<T> clazz) {
        try {
            Object value = redisTemplate.opsForValue().get(key);
            return value != null ? (T) value : null;
        } catch (Exception e) {
            log.error("获取缓存失败, key: {}", key, e);
            return null;
        }
    }

    /**
     * 递增操作
     */
    public Long increment(String key) {
        try {
            return redisTemplate.opsForValue().increment(key);
        } catch (Exception e) {
            log.error("递增操作失败, key: {}", key, e);
            return null;
        }
    }

    /**
     * 递增指定数值
     */
    public Long increment(String key, long delta) {
        try {
            return redisTemplate.opsForValue().increment(key, delta);
        } catch (Exception e) {
            log.error("递增操作失败, key: {}, delta: {}", key, delta, e);
            return null;
        }
    }

    /**
     * 递减操作
     */
    public Long decrement(String key) {
        try {
            return redisTemplate.opsForValue().decrement(key);
        } catch (Exception e) {
            log.error("递减操作失败, key: {}", key, e);
            return null;
        }
    }

    // ========== Hash操作 ==========

    /**
     * Hash设置值
     */
    public Boolean hSet(String key, Object hashKey, Object value) {
        try {
            redisTemplate.opsForHash().put(key, hashKey, value);
            return true;
        } catch (Exception e) {
            log.error("Hash设置失败, key: {}, hashKey: {}, value: {}", key, hashKey, value, e);
            return false;
        }
    }

    /**
     * Hash获取值
     */
    public Object hGet(String key, Object hashKey) {
        try {
            return redisTemplate.opsForHash().get(key, hashKey);
        } catch (Exception e) {
            log.error("Hash获取失败, key: {}, hashKey: {}", key, hashKey, e);
            return null;
        }
    }

    /**
     * Hash批量设置
     */
    public Boolean hSetAll(String key, Map<String, Object> map) {
        try {
            redisTemplate.opsForHash().putAll(key, map);
            return true;
        } catch (Exception e) {
            log.error("Hash批量设置失败, key: {}, map: {}", key, map, e);
            return false;
        }
    }

    /**
     * Hash获取所有键值对
     */
    public Map<Object, Object> hGetAll(String key) {
        try {
            return redisTemplate.opsForHash().entries(key);
        } catch (Exception e) {
            log.error("Hash获取所有键值对失败, key: {}", key, e);
            return null;
        }
    }

    /**
     * Hash删除字段
     */
    public Long hDelete(String key, Object... hashKeys) {
        try {
            return redisTemplate.opsForHash().delete(key, hashKeys);
        } catch (Exception e) {
            log.error("Hash删除字段失败, key: {}, hashKeys: {}", key, hashKeys, e);
            return 0L;
        }
    }

    /**
     * Hash判断字段是否存在
     */
    public Boolean hHasKey(String key, Object hashKey) {
        try {
            return redisTemplate.opsForHash().hasKey(key, hashKey);
        } catch (Exception e) {
            log.error("Hash判断字段存在性失败, key: {}, hashKey: {}", key, hashKey, e);
            return false;
        }
    }

    // ========== Set操作 ==========

    /**
     * Set添加元素
     */
    public Long sAdd(String key, Object... values) {
        try {
            return redisTemplate.opsForSet().add(key, values);
        } catch (Exception e) {
            log.error("Set添加元素失败, key: {}, values: {}", key, values, e);
            return 0L;
        }
    }

    /**
     * Set获取所有元素
     */
    public Set<Object> sMembers(String key) {
        try {
            return redisTemplate.opsForSet().members(key);
        } catch (Exception e) {
            log.error("Set获取所有元素失败, key: {}", key, e);
            return null;
        }
    }

    /**
     * Set判断元素是否存在
     */
    public Boolean sIsMember(String key, Object value) {
        try {
            return redisTemplate.opsForSet().isMember(key, value);
        } catch (Exception e) {
            log.error("Set判断元素存在性失败, key: {}, value: {}", key, value, e);
            return false;
        }
    }

    /**
     * Set移除元素
     */
    public Long sRemove(String key, Object... values) {
        try {
            return redisTemplate.opsForSet().remove(key, values);
        } catch (Exception e) {
            log.error("Set移除元素失败, key: {}, values: {}", key, values, e);
            return 0L;
        }
    }

    // ========== List操作 ==========

    /**
     * List右侧添加元素
     */
    public Long lPush(String key, Object... values) {
        try {
            return redisTemplate.opsForList().rightPushAll(key, values);
        } catch (Exception e) {
            log.error("List右侧添加元素失败, key: {}, values: {}", key, values, e);
            return 0L;
        }
    }

    /**
     * List左侧添加元素
     */
    public Long lLeftPush(String key, Object value) {
        try {
            return redisTemplate.opsForList().leftPush(key, value);
        } catch (Exception e) {
            log.error("List左侧添加元素失败, key: {}, value: {}", key, value, e);
            return 0L;
        }
    }

    /**
     * List获取指定范围元素
     */
    public List<Object> lRange(String key, long start, long end) {
        try {
            return redisTemplate.opsForList().range(key, start, end);
        } catch (Exception e) {
            log.error("List获取范围元素失败, key: {}, start: {}, end: {}", key, start, end, e);
            return null;
        }
    }

    /**
     * List获取长度
     */
    public Long lSize(String key) {
        try {
            return redisTemplate.opsForList().size(key);
        } catch (Exception e) {
            log.error("List获取长度失败, key: {}", key, e);
            return 0L;
        }
    }

    /**
     * List左侧弹出元素
     */
    public Object lLeftPop(String key) {
        try {
            return redisTemplate.opsForList().leftPop(key);
        } catch (Exception e) {
            log.error("List左侧弹出元素失败, key: {}", key, e);
            return null;
        }
    }

    /**
     * List右侧弹出元素
     */
    public Object lRightPop(String key) {
        try {
            return redisTemplate.opsForList().rightPop(key);
        } catch (Exception e) {
            log.error("List右侧弹出元素失败, key: {}", key, e);
            return null;
        }
    }

    // ========== 与Django后端集成的便捷方法 ==========

    /**
     * 缓存用户会话（与Django session保持一致）
     */
    public Boolean cacheUserSession(String userId, Object sessionData, long sessionTimeoutSeconds) {
        String key = "user:session:" + userId;
        return set(key, sessionData, sessionTimeoutSeconds);
    }

    /**
     * 获取用户会话
     */
    public Object getUserSession(String userId) {
        String key = "user:session:" + userId;
        return get(key);
    }

    /**
     * 缓存智能体信息
     */
    public Boolean cacheAgentInfo(String agentId, Object agentData, long cacheTimeSeconds) {
        String key = "agent:info:" + agentId;
        return set(key, agentData, cacheTimeSeconds);
    }

    /**
     * 缓存对话历史
     */
    public Boolean cacheConversation(String conversationId, Object conversationData) {
        String key = "conversation:" + conversationId;
        // 对话缓存24小时
        return set(key, conversationData, 24 * 60 * 60);
    }
}